/*********************************************************************************
 *      Copyright:  (C) 2024 LiYi<1751425323@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  mosquitto_pub.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(25/04/24)
 *         Author:  LiYi <1751425323@qq.com>
 *      ChangeLog:  1, Release initial version on "25/04/24 11:20:42"
 *                 
 ********************************************************************************/

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
#include <getopt.h>
#include <string.h>
#include <mosquitto.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <signal.h>
#include <time.h>


#include "mqtt_conf.h"
#include "cJSON.h"
#include "dictionary.h"
#include "iniparser.h"
#include "ifconfig.h"
#include "db_sqlite3.h"


#define  PROG_VERSION "1.0.0"
#define  INI_PATH "./mqtt_aliyun.ini"


static int g_stop = 0;

/*  调用信号 */
void sig_handler(int sig_num)
{
	if(sig_num == SIGUSR1)
		g_stop = 1;

}

int db_init(sqlite3  *db,char *zErrMsg);
int db_table(char *zErrMsg, sqlite3 *db);
int db_store(sqlite3 *db,char *zErrMsg);
int get_temperature(float *temper);
int get_time (char *datetime,int len);
static inline void print_usage(char *progname);
char *create_json(void *obj);
void connect_callback(struct mosquitto *mosq,void *obj,int rc);


int main (int argc, char **argv)
{
	char                        *progname = basename(argv[0]);
	int                         brokerport = 1883;
	char                        *brokeraddress = NULL;
	char                        *clientid = NULL;
	char                        *username = NULL;
	char                        *password = NULL;
	char                        *topic = NULL;
	struct mosquitto            *mosq = NULL;
	int                         daemon_run = 0;
	int                         opt = -1;
	int                         rv;
	int                         log_fd;
	struct mqtt_user_data       mqtt;
	struct option options[] = {
		{"daemon",no_argument,NULL,'d'},
		{"topic", required_argument,NULL,'t'},
		{"brokeraddress", required_argument,NULL,'H'},
		{"clientid", required_argument, NULL, 'i'},
		{"brokerport",required_argument,NULL,'p'},
		{"help",no_argument,NULL,'h'},
		{"username",required_argument,NULL,'u'},
		{"password",required_argument,NULL,'P'},
		{NULL,0,NULL,0}
	};

	while((opt = getopt_long(argc,argv,"dhp:t:i:u:P:H:",options,NULL)) != -1)
	{
		switch(opt)
		{
			case 't':
				topic = optarg;
				break;

			case 'i':
				clientid = optarg;
				break;

			case 'H':
				brokeraddress = optarg;
				break;

			case 'u':
				username = optarg;
				break;

			case 'P':
				password = optarg;
				break;

			case 'd':
				daemon_run = 1;
				break;

			case 'p':
				brokerport = atoi(optarg);
				break;

			case 'h':
				print_usage(argv[0]);
				return 0;

			default:
				break;
		}
	}

	/*  创建日志 */
	if(daemon_run)
	{
		printf("program %s running in backgrund\n", progname);
		if( (log_fd = open("client.log", O_CREAT|O_RDWR, 0666)) < 0)
		{
			printf("open() failed:%s\n", strerror(errno)) ;
			return -2;
		}

		dup2(log_fd, STDOUT_FILENO);
		dup2(log_fd, STDERR_FILENO);

		daemon(1,1);
	}

	/*  安装信号 */
	signal(SIGUSR1,sig_handler);

	/*  载入配置文件 */
	memset(&mqtt,0,sizeof(mqtt));
	rv = get_config(INI_PATH,&mqtt,PUB);

	/*  MQTT 初始化 */
	mosquitto_lib_init();

	/*  创建MQTT 客户端 */
	mosq = mosquitto_new(mqtt.clientid,true,(void *)&mqtt);

	if(!mosq)
	{
		printf("mosquitto_new() failed: %s\n",strerror(errno));
		goto cleanup;
		return -1;
	}

	/*  设置账号密码 */
	if(mosquitto_username_pw_set(mosq,mqtt.username,mqtt.password) != MOSQ_ERR_SUCCESS)
	{
		printf("mosquitto_username_pw_set failed: %s\n",strerror(errno));
		goto cleanup;
	}
	printf("Create mosquitto successfully!\n");

	/*  回调函数 */
	mosquitto_connect_callback_set(mosq,connect_callback);

	while(!g_stop)
	{
		/*  连接MQTT服务器,ip,端口,时间 */ 
		if(mosquitto_connect(mosq, mqtt.brokeraddress,mqtt.brokerport,KEEP_ALIVE) != MOSQ_ERR_SUCCESS)
		{
			printf("mosquitto_connect() failed: %s\n",strerror(errno));
			goto cleanup;
		}
		printf("connect successfully\n");

		/* 无阻塞 断线连接 */
		mosquitto_loop_forever(mosq,-1,1);
		sleep(3);
	}

	/*  释放客户端,清除 */
cleanup:
	close(log_fd);
	mosquitto_destroy(mosq);
	mosquitto_lib_cleanup();
	return 0;
}


void print_usage(char *progname)
{
	printf("%s usage:\n",progname);
	printf("Example: %s -h ${brokeraddress} -p ${brokerport} -i ${clientid} -u ${username} -p ${password} -t${topic} -h ${help} -d ${daemon}\n",progname);
	printf("-h(--host): sepcify brokeraddress.\n");
	printf("-p(--port): sepcify brokerport.\n");
	printf("-h(--Help): print this help information.\n");
	printf("-d(--daemon): set program running on background.\n");
	printf("-i(--clientid): sepcify the clientid.\n");
	printf("-u(--username): sepcify username of the client.\n");
	printf("-p(--password): sepcify password of the username.\n");
	printf("-t(--topic): sepcify topic of the client.\n");
	printf("-d(--daemon): running in backgrund.\n");
}


/*  cJSON打包数据 */
void connect_callback(struct mosquitto *mosq,void *obj,int rc)
{
	char                    ipaddr[16];
	char                    *interface="eth0";
	char                    datetime[64];
	cJSON                   *root;
	cJSON                   *item;
	char                    *msg;
	struct mqtt_user_data   *mqtt;
	char                    buf[2048];

	printf("Connection successful cJSON call packaging\n");

	float temper = 0.00000000;
	if(get_temperature(&temper) < 0)
	{
		printf("get_temperature failed.\n");
		return;
	}

	if(get_time(datetime,sizeof(datetime))<0)
	{
		printf("get_time failure\n");
		return ;
	}

	memset(ipaddr,0,sizeof(ipaddr));
	if(get_ipaddr(interface,ipaddr,sizeof(ipaddr))<0)
	{
		printf("ERROR:get ip address failure\n");
		return ;
	}

	snprintf(buf,sizeof(buf),"%s/%s/%f",ipaddr,datetime,temper);
	sqlite_tem(buf);
	printf("Data transfer database successfully!\n");
	printf("\n");

	root = cJSON_CreateObject();
	item = cJSON_CreateObject();

	if(!obj)
	{
		printf("invalid_argument in %s\n",__FUNCTION__);
		return;
	}

	mqtt = (mqtt_user_data *)obj;

	cJSON_AddItemToObject(root,"method",cJSON_CreateString(mqtt->method));
	cJSON_AddItemToObject(root,"id",cJSON_CreateString(ipaddr));
	cJSON_AddItemToObject(root,"time",cJSON_CreateString(datetime));
	cJSON_AddItemToObject(root,"params",item);
	cJSON_AddItemToObject(item,"temperature",cJSON_CreateNumber(temper));
	cJSON_AddItemToObject(root,"version",cJSON_CreateString(mqtt->version));

	msg = cJSON_Print(root);
	printf("%s\n",msg);

	if(!rc)
	{
		if(mosquitto_publish(mosq,NULL,mqtt->topic,strlen(msg),msg,mqtt->Qos,NULL) != MOSQ_ERR_SUCCESS)
		{
			printf("mosquitto_publish failed: %s\n",strerror(errno));
			return;
		}
	}
	mosquitto_disconnect(mosq);
}


int get_temperature(float *temper)
{
	char            w1_path[64] = "/sys/bus/w1/devices/";
	char            chip[32];
	char            buf[128];
	DIR            *dirp;
	struct dirent  *direntp;
	int             fd = -1;
	char           *ptr;
	int             found = 0;

	if( !temper )
	{
		return -1;
	}

	if((dirp = opendir(w1_path)) == NULL)
	{
		printf("Opendir '%s' error: %s\n", w1_path, strerror(errno));
		return -2;
	}

	while((direntp = readdir(dirp)) != NULL)
	{
		if(strstr(direntp->d_name,"28-"))
		{
			strncpy(chip, direntp->d_name, sizeof(chip));
			found = 1;
			break;
		}
	}

	closedir(dirp);

	if( !found )
	{
		printf("Can not find ds18b20 in '%s'\n", w1_path);
		return -3;
	}

	strncat(w1_path, chip, sizeof(w1_path)-strlen(w1_path));
	strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path));

	if( (fd=open(w1_path, O_RDONLY)) < 0 ) 
	{ 
		printf("open %s error: %s\n", w1_path, strerror(errno)); 
		return -4;
	} 

	if(read(fd, buf, sizeof(buf)) < 0)
	{
		printf("read %s error: %s\n", w1_path, strerror(errno)); 
		return -5;
	} 

	ptr = strstr(buf, "t=");
	if( !ptr )
	{
		printf("ERROR: Can not get temperature\n");
		return -6;
	}

	*temper = atof(ptr+=2)/1000;

	close(fd);
	return 0;
}

/*  获取时间 */
int get_time(char *datime,int len)
{
	time_t          t;
	struct tm       *p;

	time(&t);
	p = gmtime(&t);

	snprintf(datime, 32, "%d-%d-%d %d:%d:%d", 1900+p->tm_year,1+p->tm_mon, p->tm_mday, (p->tm_hour + 8), p->tm_min, p->tm_sec);
	return 0 ;
}


